package fr.upmc.aladyn.methodcallinterception;

import fr.upmc.aladyn.annotation.Transactionable;
import fr.upmc.aladyn.shared.ObjectSingleton;
import javassist.tools.reflect.Metaobject;


/**
 * Class extending the Metaobject class. In this case, it allows us to redefine 
 * the way we react when a method is called and to add treatment in the code to 
 * dynamically modify it's behaviour
 * 
 * @author Thierry Wong
 * @author Seyyid ahmed Ouir 
 */
public class MyMetaObject extends Metaobject{
	
	private static final long serialVersionUID = 1L;

	public MyMetaObject(java.lang.Object self, java.lang.Object[] args)
	{
		super(self, args);
	}
	
	@Override
	public Object trapMethodcall(int arg0, Object[] arg1) throws Throwable
	{
		if (super.getMethodName(arg0).startsWith("set"))
		{
			System.out.println("[In setter : " + 
								super.getMethodName(arg0) + "]");
			ObjectSingleton.getInstance().sauvegarder(super.getObject());
			return super.trapMethodcall(arg0, arg1);
		}
		
		if (super.methods[arg0].isAnnotationPresent(Transactionable.class)
				){
			System.out.println("[In transactionable method : " + 
								super.methods[arg0].getName() + "]");
			ObjectSingleton.getInstance().debutMethodeTrans();
			try{
				return super.trapMethodcall(arg0, arg1);			
			}
			catch (Exception e)
			{
				System.out.println("[Intercepted an exception. Restoration]\n");
				ObjectSingleton.getInstance().restaurer();
				System.out.println("[Finished restoration]\n");
				// We return e instead of throwing it again to be able to 
				// print values
				return e;
			}
			finally
			{
				System.out.println("[Cleaning of attached environment]\n");
				ObjectSingleton.getInstance().finMethodeTrans();
				System.out.println("[Cleaning finished]\n");
			}
		}
		return super.trapMethodcall(arg0, arg1);
	}

}
